社区分享|如何让模型在生产环境上推理得更快
本文来自社区投稿与征集,作者:孔晓泉,Google Developers Expert,TensorFlow Core&Addons contributor。
可以同时服务多个模型或同一模型的多个版本 支持使用 gRPC 和 HTTP 进行推理 允许部署新模型版本,而无需更改任何客户端代码 支持灰度发布新版本和 A/B 测试实验性模型 高效且低消耗的代码实现,可将推理的时间延迟降至最低 内置一个可配置的调度器,可以将多个单推理合并成一个批推理,在可控的少许增加延迟的基础上,大大的提高系统吞吐量 支持多种服务对象:TensorFlow 模型、embedding、词汇表和特征转换等,甚至能支持非基于 TensorFlow 的模型
毋庸置疑,TensorFlow Serving 是在云端和普通 PC 环境部署模型的最佳选择。
在实际使用中,我们还可以采用如下几种方案来进一步的发挥 TensorFlow Serving 的性能优势。
PS: 由于每种方案的性能提升效果和模型类型、网络结构、硬件情况、以及请求负荷存在较大关联,本文无法给出一个合理的评估,因此没有提及效果改进情况,具体提升效果需要用户实地测量。
构建最优化的 TensorFlow Serving
无论是使用 GPU 还是完全使用 CPU 进行推理,CPU 的速度对于推理速度都是有着直接的影响的。对于较新的 CPU 而言,有些高级的计算特性并没有被默认的 TensorFlow Serving 二进制可执行代码所采用(之所以采用这种策略,是为了让默认的 TensorFlow 可以保持对老设备的兼容性)。
我们可以重新构建 TensorFlow Serving 的二进制可执行代码,从而发挥 CPU 的全部能力。
检查 CPU 支持情况
在实施这一方案前,需要检查生产环境的 CPU 是否含有某些 TensorFlow Serving 默认没有启用的特性。TensorFlow Serving 在这方面提供了良好的 log 输出,我们直接可以通过寻找 log 中的信息即可。
在使用默认的 TensorFlow Serving 的二进制可执行代码(通常是 Docker image,这是官方推荐的方式)进行推理时,如果 log 中有如下信息,那么说明当前的 CPU 比较新,有一些 TensorFlow Serving 默认没有启用的高级特性。
Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
如果没有找到上述信息,那么说明该 CPU 的特性已经得到了最大程度的利用,「充分利用 CPU 特性」这一方案并不适用于该 CPU。
编译 TensorFlow Serving
如果在上一步中,确实存在没有充分利用的 CPU 特性,那么我们就可以通过自行构建 TensorFlow Serving 二进制可执行代码的方式,将这部分特性利用起来,加速推理。
官方推荐的也是最常见和最简单的 TensorFlow Serving 使用模式,就是使用其 Docker 镜像。这一节,我们将介绍如何构建定制的 TensorFlow Serving Docker 镜像。同样非常的简单。
1. 克隆 TensorFlow Serving 项目
git clone https://github.com/tensorflow/serving
cd serving
2. 构建 develop 镜像
for CPU
docker build --pull -t $USER/tensorflow-serving-devel \
-f tensorflow_serving/tools/docker/Dockerfile.devel .
for GPU
docker build --pull -t $USER/tensorflow-serving-devel-gpu \
-f tensorflow_serving/tools/docker/Dockerfile.devel-gpu .
3. 构建 serving 镜像
for CPU
docker build -t $USER/tensorflow-serving \
--build-arg TF_SERVING_BUILD_IMAGE=$USER/tensorflow-serving-devel \
-f tensorflow_serving/tools/docker/Dockerfile .
至此,你得到了一个名为 $USER/tensorflow-serving
的优化过的镜像,其使用方法和标准的 tensorflow/serving:latest 完全一样。
for GPU
docker build -t $USER/tensorflow-serving-gpu \
--build-arg TF_SERVING_BUILD_IMAGE=$USER/tensorflow-serving-devel-gpu \
-f tensorflow_serving/tools/docker/Dockerfile.gpu .
至此,你得到了一个名为 $USER/tensorflow-serving-gpu
的优化过的镜像,其使用方法和标准的 tensorflow/serving:latest-gpu
完全一样。
更多信息
请参考文章最底部的「相关内容」区域的 「TensorFlow Serving - Developing with Docker」和「How we improved Tensorflow Serving performance by over 70%」
使用批量推理增加系统吞吐量
批量推理是将一个个小的独立的请求合并成一个大的批量的请求。通过批量推理的方式,可以在少许增加推理延迟的代价下,大幅度节约计算资源,极大的提高系统吞吐量。
理论上,批量推理可以有三种基本的模式,分别是:服务端批量推理、客户端批量推理和中间件批量推理。
客户端批量推理是指客户端自行将多个请求合并成一个批量请求,然后进行推理。中间件批量推理以中间件的形式介于客户端和服务端之间,透明的将客户端的单个请求聚合成批量请求,发送到服务端完成推理后,再逐一返回相应的客户端。由于 TensorFlow Serving 自带的服务端批量推理在功能强大的同时性能优异,适用面广泛,因此在生产环境中几乎毫无例外的采用服务端批量推理。
服务端批量推理是 Tensorflow Serving 开箱即用的特性之一。毫不夸张的说,服务端批量推理是最强大但又没有引起注意的 TensorFlow Serving 特性,能非常有效的利用 CPU 和 GPU 硬件。尤其对于那些特别消耗内存的模型,特别适用。
配置批量推理参数
TensorFlow Serving 支持用户对批量推理的过程进行配置,而这个配置是通过配置文件的形式体现的。如下是一个配置文件内容的示例。
max_batch_size { value: 128 }
batch_timeout_micros { value: 0 }
max_enqueued_batches { value: 1000000 }
num_batch_threads { value: 8 }
1. max_batch_size
该参数用来指定一个批次中最大的请求数量。此参数控制吞吐量/延迟权衡,设置小的值会获得较低的延迟和较低的吞吐量,设置较大的值会获得较高的延迟和较大的吞吐量。将该参数设置的过大,可能会导致因超过某些资源限制的情况(例如 GPU 内存)而带来的错误。
2. batch_timeout_micros
这个参数用于控制执行批处理之前等待的最长时间(即使尚未达到 max_batch_size)。用于控制尾部延迟(tail latency)。
3. max_enqueued_batches
这个参数用于控制并行度,即同时处理的最大批次数。
4. num_batch_threads
这个参数可以控制加入队列的批处理任务的数量。超过这个数量后,系统将会通过拒绝需要很长时间才能开始处理的请求来限制队列的延迟,如果对队列元素数量不加控制,会造成大量积压请求,所有任务的延迟都会很高。
启用批量推理并指定配置文件路径
在启动 TensorFlow Serving docker 镜像时,设置 --enable_batching
就可以启动批量推理,同时需要通过 --batching_parameters_file 指定配置文件的路径。
更多信息
请参考文章最底部的「相关内容」区域的 「Tensorflow Serving Configuration」和 「TensorFlow Serving Batching Guide」。
减少信道延迟
TensorFlow Serving 支持两种信道:gRPC 和 HTTP,这两者间存在一定的差异,在生产环境中,应该使用基于 gRPC 的方式进行推理。
gRPC 和 HTTP 信道的对比
HTTP 容易实现和调试 gRPC 网络通讯效率更高,payloads 更小 gRPC 可以提供更快的推理 有极少数不常用的特性,只有 gRPC 支持
更多信息
请参考文章最底部的「相关内容」区域的 「Advanced model deployments with TensorFlow Serving Presentation」。
使用 NVIDIA TensorRT
NVIDIA TensorRT 是 NVIDIA 公司推出的,用于高性能深度学习推理的平台。它包括了推理优化器和运行时,可以降低模型推理的延迟和提高系统吞吐量。TensorRT 是基于 CUDA 平台的,而 CUDA 目前只支持 NVIDIA 的部分 GPU。因此这个方案仅适合服务器上具有 NVIDIA GPU 的场景。
TensorFlow Serving 支持无缝集成 TensorRT,只需若干步骤即可完成转换。
模型转换
下面的命令将会把普通的 SavedModel 模型转换成 TensorRT 模型。
待转换的模型位于 /tmp/resnet/1538687457,转换后的模型位于 /tmp/resnet_trt/1538687457
docker pull tensorflow/tensorflow:latest-gpu
docker run --rm --runtime=nvidia -it \
-v /tmp:/tmp tensorflow/tensorflow:latest-gpu \
/usr/local/bin/saved_model_cli convert \
--dir /tmp/resnet/1538687457 \
--output_dir /tmp/resnet_trt/1538687457 \
--tag_set serve \
tensorrt --precision_mode FP32 --max_batch_size 1 --is_dynamic_op True
--precision_mode 设置精度模型,目前只支持 FP32 and FP16。 --max_batch_size 设置最大的批量推理大小。实际请求大小可以小于这个尺寸,但是不能超过。 --is_dynamic_op 设置模型转换发生在模型运行时。这是因为 TensorRT 要求在转换时,所有 Tensor 的 shape 都必须固定下来。有些模型并没有固定的 shape,所以需要这个参数。
运行
转换后的 TensorRT 模型,和其他普通的 SavedModel 模型使用起来并没有任何不同:
docker run --rm --runtime=nvidia -p 8501:8501 \
--name tfserving_resnet \
-v /tmp/resnet_trt:/models/resnet \
-e MODEL_NAME=resnet \
-t tensorflow/serving:latest-gpu
更多信息
请参考文章最底部的「相关内容」区域的 「Optimizing TensorFlow Serving performance with NVIDIA TensorRT」。
使用 TensorFlow Lite 模型
TensorFlow Lite 是针对低功耗、低算力场景而特别优化的框架。TensorFlow Lite 模型可以利用量化、剪枝等技术优化模型尺寸和推理速度。TensorFlow Serving 支持直接加载 TensorFlow Lite 模型,从而直接提高推理速度。
需要注意:写作之时,TensorFlow Serving 对 TensorFlow Lite 模型的支持仍属于实验特性,需要小心使用。同时由于 TensorFlow Lite 尚未支持全部算子,所以可能有些模型无法成功转换。
转换成 TensorFlow Lite 模型
SavedModel 模型需要转换成 TensorFlow Lite 模型,在这转换过程中,转换器可以按照指定的优化策略对模型进行优化。
import tensorflow as tf
saved_model_dir = "path_to_saved_model"
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()
with open("/tmp/model.tflite", "wb") as f:
f.write(tflite_model)
运行 TensorFlow Lite 模型
和普通的 SavedModel 不同的是,运行 TensorFlow Lite 模型时需要明确的设定 --use_tflite_model=true
。
docker run -p 8501:8501 \
--mount type=bind,source=/path/to/models,target=/models/my_model \
-e MODEL_BASE_PATH=/models \
-e MODEL_NAME=my_model \
-t tensorflow/serving:latest \
--use_tflite_model=true
更多信息
请参考文章最底部的「相关内容」区域的 「Advanced model deployments with TensorFlow Serving Presentation」和「Get started with TensorFlow Lite」。
如果您想详细了解 本文讨论 的相关内容,请参阅以下文档。这些文档深入探讨了这篇文章中提及的许多主题:
TensorFlow Serving - Developing with Docker
https://github.com/tensorflow/serving/blob/master/tensorflow_serving/g3doc/building_with_docker.mdHow we improved Tensorflow Serving performance by over 70%
https://hackernoon.com/how-we-improved-tensorflow-serving-performance-by-over-70-f21b5dad2d98Optimizing TensorFlow Serving performance with NVIDIA TensorRT
https://medium.com/tensorflow/optimizing-tensorflow-serving-performance-with-nvidia-tensorrt-6d8a2347869aTensorFlow Serving Batching Guide
https://github.com/tensorflow/serving/blob/master/tensorflow_serving/batching/README.mdTensorflow Serving Configuration
https://www.tensorflow.org/tfx/serving/serving_configAdvanced model deployments with TensorFlow Serving Presentation
https://cdn.oreillystatic.com/en/assets/1/event/308/Advanced%20model%20deployments%20with%20TensorFlow%20Serving%20Presentation.pdfGet started with TensorFlow Lite
https://www.tensorflow.org/lite/guide/get_started